package com.zhj.java8.stream;

import com.zhj.java8.bean.Student;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.TreeSet;
import java.util.stream.Stream;

import static java.util.stream.Collectors.collectingAndThen;
import static java.util.stream.Collectors.toCollection;


public class MiddleStreamDemo {

    public static void main(String[] args) {

        List<Student> students = new ArrayList<>();
        students.add(new Student(1,"小华",23,1));
        students.add(new Student(1,"小华",23,2));
        students.add(new Student(2,"小米",20,2));
        students.add(new Student(3,"小果",30,3));
        students.add(new Student(4,"小维",18,2));

        // 过滤
        students.stream().filter(stu -> stu.getAge() > 20).forEach(System.out::println);

        // 去重
        // 对对象去重是根据引用去重，内容重复并不会去重，除非重写equals和hashCode方法
        System.out.println("----------去重----------");
        System.out.println("去重1----------");
        students.stream().distinct().forEach(System.out::println);
        // 对集合中对象某些属性去重，不重写equals和hashCode方法，只能借助其他数据结构来辅助去重
        // 单个属性可以stu -> stu.getId()
        // 多个属性可以stu -> stu.getId() + ";" + stu.getName()
        System.out.println("去重2----------");
        ArrayList<Student> distinctList = students.stream().collect(
                collectingAndThen(toCollection(() -> new TreeSet<>(Comparator.comparing(stu -> stu.getId() + ";" + stu.getName()))), ArrayList::new)
        );
        distinctList.stream().forEach(System.out::println);

        // 排序 支持定义排序方式
        // sorted 默认使用 自然序排序， 其中的元素必须实现Comparable 接口
        System.out.println("----------排序----------");
        System.out.println("排序1----------");
        students.stream().sorted().forEach(System.out::println);
        // sorted(Comparator<? super T> comparator) ：我们可以使用lambada 来创建一个Comparator 实例。可以按照升序或着降序来排序元素。
        System.out.println("排序2----------");
        students.stream()
                .sorted(Comparator.comparing(Student::getAge,Comparator.reverseOrder())) // ,Comparator.reverseOrder() 逆序
                .forEach(System.out::println);
        // 创建比较器，通过对比较器内容的定义实现对多个属性进行排序，类似sql中连续的orderBy
        System.out.println("排序3----------");
        students.stream().sorted(
                (s1,s2) -> {
                    if (s1.getAge() == s2.getAge()) {
                        return s1.getSex().compareTo(s2.getSex());
                    } else {
                        return -s1.getAge().compareTo(s2.getAge());
                    }
                }
        ).forEach(System.out::println);
        System.out.println("排序4----------");
        Comparator<Student> studentComparator = (s1,s2) -> {
            Integer age1 = s1.getAge();
            Integer age2 = s2.getAge();
            if (age1 != age2) return age1 - age2;
            Integer sex1 = s1.getSex();
            Integer sex2 = s2.getSex();
            if (sex1 != sex2) return sex2 - sex1;
            return 0;
        };
        students.stream().sorted(studentComparator).forEach(System.out::println);

        // 截取 截取前三个元素
        System.out.println("----------截取----------");
        students.stream().limit(3).forEach(System.out::println);

        // 跳过 跳过前3个元素
        System.out.println("----------跳过----------");
        students.stream().skip(3).forEach(System.out::println);

        // 映射
        System.out.println("----------映射----------");
        System.out.println("映射Map----------");
        // map接收Lambda,将元素转换其他形式，或者是提取信息，并将其映射成一个新的元素
        Stream<Stream<Student>> streamStream1 = students.stream().map(str -> filterStudent(str));
        streamStream1.forEach(sm -> sm.forEach(System.out::println));
        System.out.println("映射flatMap----------");
        // map接收Lambda,将流中的每一个元素转换成另一个流，然后把所有流连成一个流 扁平化映射
        Stream<Student> studentStream2 = students.stream().flatMap(str -> filterStudent(str));
        studentStream2.forEach(System.out::println);

        // 消费
        System.out.println("----------消费----------");
        students.stream().peek(stu -> stu.setAge(100)).forEach(System.out::println);
    }

    public static Stream<Student> filterStudent(Student student) {
        student = new Student();
        return Stream.of(student);
    }
}
